/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package platform;

import cryptography.HashWrapper;
import cryptography.HmacSHA1;
import cryptography.TenorRandomGenerator;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.Mac;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import zorg.CryptoException;
import zorg.platform.CryptoUtils;
import zorg.platform.DiffieHellmanSuite;
import zorg.platform.Digest;
import zorg.platform.EncryptorSuite;
import zorg.platform.HMAC;
import zorg.platform.RandomGenerator;

/**
 *
 * @author Tomasz Nowak
 */
public class TenorCryptoUtils implements CryptoUtils
{
	@Override
	public Digest createDigestSHA1()
	{
		try
		{
			return new HashWrapper("SHA-1");
		}
		catch ( NoSuchAlgorithmException ex )
		{
			Logger.getLogger(TenorCryptoUtils.class.getName()).log(Level.SEVERE, null, ex);
			return null;
		}
	}

	@Override
	public Digest createDigestSHA256()
	{
		try
		{
			return new HashWrapper("SHA-256");
		}
		catch ( NoSuchAlgorithmException ex )
		{
			Logger.getLogger(TenorCryptoUtils.class.getName()).log(Level.SEVERE, null, ex);
			return null;
		}
	}

	@Override
	public Digest createDigestSHA384()
	{
		try
		{
			return new HashWrapper("SHA-384");
		}
		catch ( NoSuchAlgorithmException ex )
		{
			Logger.getLogger(TenorCryptoUtils.class.getName()).log(Level.SEVERE, null, ex);
			return null;
		}
	}

	@Override
	public byte[] calculateSHA256HMAC( byte[] data, int offset, int length, byte[] aKey )
	{
		return calculateHmac("HmacSHA256", subArray(data, offset, length), aKey);
	}

	@Override
	public byte[] calculateSHA384HMAC( byte[] data, int offset, int length, byte[] aKey )
	{
		return calculateHmac("HmacSHA384", subArray(data, offset, length), aKey);
	}

	@Override
	public HMAC createHMACSHA1( byte[] hmacKey ) throws CryptoException
	{
		try
		{
			return new HmacSHA1(hmacKey);
		}
		catch ( NoSuchAlgorithmException ex )
		{
			Logger.getLogger(TenorCryptoUtils.class.getName()).log(Level.SEVERE, null, ex);
			return null;
		}
	}

	@Override
	public RandomGenerator getRandomGenerator()
	{
		return TenorRandomGenerator.getInstance();
	}

	@Override
	public byte[] aesEncrypt( byte[] data, byte[] key, byte[] initVector ) throws CryptoException
	{
		try
		{
			Cipher cipher;
			cipher = Cipher.getInstance("AES");
			cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, cipher.getAlgorithm()), new IvParameterSpec(initVector));
			return cipher.doFinal(data);
		}
		catch ( NoSuchAlgorithmException ex )
		{
			Logger.getLogger(TenorCryptoUtils.class.getName()).log(Level.SEVERE, null, ex);
		}
		catch ( NoSuchPaddingException ex )
		{
			Logger.getLogger(TenorCryptoUtils.class.getName()).log(Level.SEVERE, null, ex);
		}
		catch ( InvalidKeyException ex )
		{
			Logger.getLogger(TenorCryptoUtils.class.getName()).log(Level.SEVERE, null, ex);
		}
		catch ( InvalidAlgorithmParameterException ex )
		{
			Logger.getLogger(TenorCryptoUtils.class.getName()).log(Level.SEVERE, null, ex);
		}
		catch ( IllegalBlockSizeException ex )
		{
			Logger.getLogger(TenorCryptoUtils.class.getName()).log(Level.SEVERE, null, ex);
		}
		catch ( BadPaddingException ex )
		{
			Logger.getLogger(TenorCryptoUtils.class.getName()).log(Level.SEVERE, null, ex);
		}
		return null;
	}

	@Override
	public byte[] aesDecrypt( byte[] data, int offset, int length, byte[] key, byte[] initVector ) throws CryptoException
	{
		try
		{
			Cipher cipher;
			cipher = Cipher.getInstance("AES");
			cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key, cipher.getAlgorithm()), new IvParameterSpec(initVector));
			return cipher.doFinal(subArray(data, offset, length));
		}
		catch ( NoSuchAlgorithmException ex )
		{
			Logger.getLogger(TenorCryptoUtils.class.getName()).log(Level.SEVERE, null, ex);
		}
		catch ( NoSuchPaddingException ex )
		{
			Logger.getLogger(TenorCryptoUtils.class.getName()).log(Level.SEVERE, null, ex);
		}
		catch ( InvalidKeyException ex )
		{
			Logger.getLogger(TenorCryptoUtils.class.getName()).log(Level.SEVERE, null, ex);
		}
		catch ( InvalidAlgorithmParameterException ex )
		{
			Logger.getLogger(TenorCryptoUtils.class.getName()).log(Level.SEVERE, null, ex);
		}
		catch ( IllegalBlockSizeException ex )
		{
			Logger.getLogger(TenorCryptoUtils.class.getName()).log(Level.SEVERE, null, ex);
		}
		catch ( BadPaddingException ex )
		{
			Logger.getLogger(TenorCryptoUtils.class.getName()).log(Level.SEVERE, null, ex);
		}
		return null;
	}

	@Override
	public DiffieHellmanSuite createDHSuite()
	{
		return new TenorDHSuite();
	}

	@Override
	public EncryptorSuite createEncryptorSuite( byte[] key, byte[] initVector ) throws CryptoException
	{
		return new TenorEncryptorSuite(key, initVector);
	}

	private static byte[] calculateHmac( String algorithm, byte[] bytes, byte[] aKey )
	{
		Mac mac;
		try
		{
			mac = Mac.getInstance(algorithm);
			SecretKeySpec key = new SecretKeySpec(aKey, algorithm);
			mac.init(key);
			return mac.doFinal(aKey);
		}
		catch ( NoSuchAlgorithmException ex )
		{
			Logger.getLogger(TenorCryptoUtils.class.getName()).log(Level.SEVERE, null, ex);
			return null;
		}
		catch ( InvalidKeyException ex )
		{
			Logger.getLogger(TenorCryptoUtils.class.getName()).log(Level.SEVERE, null, ex);
			return null;
		}
	}

	static public byte[] subArray( byte[] bytes, int offset, int length )
	{
		byte[] newArray = new byte[bytes.length - offset < length ? bytes.length - offset : length];
		for ( int i = 0; i < newArray.length; ++i )
		{
			newArray[i] = bytes[i + offset];
		}
		return newArray;
	}
}
